﻿using LxBasic;
using LxCore;
using System;
using System.Reflection;
using System.Text;

namespace LxCore
{
    public partial class MonitorCenter : JsObject
    {
        public ResidualMonitorCenter ResidualMonitors { get; set; } = new();
        public UserMonitorList UserMonitors { get; set; } = new();

        protected StringBuilder ReportBuilder = new();

        public void CheckCreate()
        {
            ResidualMonitors.CheckCreate();
        }
        public void ClearHistory()
        {
            foreach (var s in ResidualMonitors.ActiveResidualMonitors)
            {
                s.ClearHistory();
            }
            ResidualMonitors.ActiveResidualMonitors.Clear();
            foreach (var s in UserMonitors)
            {
                s.ClearHistory();
            }
        }
        protected void RunMonitor(MonitorBase monitor, double x)
        {
            monitor.RunStatistic();
            ReportBuilder.Append($"{monitor.Name}:{(monitor.IsLatestValueValid ? monitor.LatestValue.ToString("e4") : "invalid")}  ");
            monitor.AddHistoryData(x, monitor.GetValue());
        }
        public void RunMonitors_Steady()
        {
            int totalStep = LxSim.Sim.Steps.CurrentTotalStep;
            ReportBuilder.Append($"总步数:{totalStep}  ");
            if (LxSim.Sim.Physics.IsImplicitTrans)
            {
                ReportBuilder.Append($"内迭代:{LxSim.Sim.Steps.IterationStep.CurrentStep}  ");
            }
            foreach (var s in ResidualMonitors.ActiveResidualMonitors)
            {
                RunMonitor(s, totalStep);
            }
            foreach (var m in UserMonitors)
            {
                if (m.MonitorTrigerType == MonitorTrigerTypes.Iteration)
                {
                    RunMonitor(m, totalStep);
                }
            }
            LxLog.Calc(ReportBuilder.ToString());
            ReportBuilder.Clear();
        }
        public void RunMonitors_Transient()
        {
            double curTime = LxSim.Sim.Steps.TimeStep.CurrentTime;
            ReportBuilder.Append($"时间步:{LxSim.Sim.Steps.TimeStep.CurrentStep}  时间:{curTime}  ");
            foreach (var m in UserMonitors)
            {
                if (m.MonitorTrigerType == MonitorTrigerTypes.TimeStep)
                {
                    RunMonitor(m, curTime);
                }
            }
            LxLog.Calc(ReportBuilder.ToString());
            ReportBuilder.Clear();
        }
        public UserMonitor CreateMonitor(string name = null, StatisticTypes statisticType = StatisticTypes.Mean)
        {
            UserMonitor um = new();
            if (!string.IsNullOrEmpty(name))
            {
                um.Name = name;
            }
            um.StatisticType = statisticType;
            UserMonitors.Add(um);

            return um;
        }
        public void RemoveMonitorAt(int id)
        {
            if (id >= 0 && id < UserMonitors.Count)
            {
                foreach (var z in LxSim.Sim.Conditions.ZoneConds)
                {
                    z.InnerCond.MonitorSelector.RemoveAt(id);
                    foreach (var f in z.BoundConds)
                    {
                        f.MonitorSelector.RemoveAt(id);
                    }
                }
                UserMonitors.RemoveAt(id);
                for (int i = id; i < UserMonitors.Count; i++)
                {
                    UserMonitors[i].ID = i;
                }
            }
        }
        public override void FromJsonKV(string key, IJsonReader jsReader)
        {
            switch (key)
            {
                case nameof(ResidualMonitors): jsReader.ReadObject(ResidualMonitors); break;
                case nameof(UserMonitors): jsReader.ReadList(UserMonitors, t => new UserMonitor()); break;
                default: base.FromJsonKV(key, jsReader); break;
            }
        }
        public override void ToJsonKV(IJsonWriter jsWriter)
        {
            base.ToJsonKV(jsWriter);
            jsWriter.WriteObject(nameof(ResidualMonitors), ResidualMonitors);
            jsWriter.WriteList(nameof(UserMonitors), UserMonitors);
        }
        public class UserMonitorList : JsIdentifyList<UserMonitor>
        {
            public override void Add(UserMonitor item)
            {
                base.Add(item);
                foreach (var z in LxSim.Sim.Conditions.ZoneConds)
                {
                    z.InnerCond.MonitorSelector.Add(false);
                    foreach (var f in z.BoundConds)
                    {
                        f.MonitorSelector.Add(false);
                    }
                }
            }
            public override void Insert(int index, UserMonitor item)
            {
                base.Insert(index, item);
                foreach (var z in LxSim.Sim.Conditions.ZoneConds)
                {
                    z.InnerCond.MonitorSelector.Insert(index, false);
                    foreach (var f in z.BoundConds)
                    {
                        f.MonitorSelector.Insert(index, false);
                    }
                }
            }
            public override bool Remove(UserMonitor item)
            {
                int index = item.ID;
                if (base.Remove(item))
                {
                    foreach (var z in LxSim.Sim.Conditions.ZoneConds)
                    {
                        z.InnerCond.MonitorSelector.RemoveAt(index);
                        foreach (var f in z.BoundConds)
                        {
                            f.MonitorSelector.RemoveAt(index);
                        }
                    }
                    return true;
                }
                else
                {
                    return false;
                }
            }
            public override void RemoveAt(int index)
            {
                base.RemoveAt(index);
                foreach (var z in LxSim.Sim.Conditions.ZoneConds)
                {
                    z.InnerCond.MonitorSelector.RemoveAt(index);
                    foreach (var f in z.BoundConds)
                    {
                        f.MonitorSelector.RemoveAt(index);
                    }
                }
            }
            public override void Clear()
            {
                base.Clear();
                foreach (var z in LxSim.Sim.Conditions.ZoneConds)
                {
                    z.InnerCond.MonitorSelector.Clear();
                    foreach (var f in z.BoundConds)
                    {
                        f.MonitorSelector.Clear();
                    }
                }
            }

        }
    }
}
